{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 文件\n",
    "- 长久保存信息的一种数据信息集合\n",
    "- 常用操作\n",
    "    - 打开关闭（文件一旦打开，需要关闭操作）\n",
    "    - 读写内容\n",
    "    - 查找\n",
    "# open函数\n",
    "- open函数负责打开文件，带有很多参数\n",
    "- 第一个参数： 必须有，文件的路径和名称\n",
    "- mode：表明文件用什么方式打开\n",
    "    - r:以只读方式打开\n",
    "    - w：写方式打开，会覆盖以前的内容\n",
    "    - x：创建方式打开，如文件已经存在，报错\n",
    "    - a：append方式，以追加的方式对文件内容进行写入\n",
    "    - b： binary方式，二进制方式写入\n",
    "    - t： 文本方式打开\n",
    "    - +： 可读写"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 打开文件，用写的方式\n",
    "# r表示后面字符串内容不需要转义\n",
    "# f称之为文件句柄\n",
    "f = open(r\"test01.txt\", 'w')\n",
    "# 文件打开后必须关闭\n",
    "f.close()\n",
    "\n",
    "# 此案例说明，以写方式打开文件，默认是如果没有文件，则创建"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# with语句\n",
    "- with语句使用的技术是一种成为上下文管理协议的技术(ContextManagementProtocal)\n",
    "- 自动判断文件的 作用域， 自动关闭不在使用的打开的文件句柄"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# with语句案例\n",
    "\n",
    "with open(r\"test01.txt\", 'r') as f:\n",
    "    pass\n",
    "    # 下面语句块开始对文件f进行操作\n",
    "    # 在本模块中不需要在使用close关闭文件f"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "假若他日相逢\n",
      "\n",
      "我将何以贺你\n",
      "\n",
      "以沉默\n",
      "\n",
      "以眼泪\n"
     ]
    }
   ],
   "source": [
    "# with案例\n",
    "\n",
    "with open(r'test01.txt', 'r') as f:\n",
    "    # 按行读取内容\n",
    "    strline = f.readline()\n",
    "    # 此结构保证能够完整读取文件知道结束\n",
    "    while strline:\n",
    "        print(strline)\n",
    "        strline = f.readline()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "假若他日相逢\n",
      "\n",
      "我将何以贺你\n",
      "\n",
      "以沉默\n",
      "\n",
      "以眼泪\n"
     ]
    }
   ],
   "source": [
    "# list能用打开的文件作为参数，把文件内每一行内容作为一个元素\n",
    "\n",
    "with open(r'test01.txt', 'r') as f:\n",
    "    # 以打开的文件f作为参数，创建列表\n",
    "    l = list(f)\n",
    "    for line in l:\n",
    "        print(line)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "假\n"
     ]
    }
   ],
   "source": [
    "# read是按字符读取文件内容\n",
    "# 允许输入参数决定读取几个字符，如果没有制定，从当前位置读取到结尾\n",
    "# 否则，从当前位置读取指定个数字符\n",
    "\n",
    "with open(r'test01.txt', 'r') as f:\n",
    "    strChar = f.read(1)\n",
    "    print(len(strChar))\n",
    "    print(strChar)\n",
    "    \n",
    "# 作业：\n",
    "# 使用read读取文件，每次读取一个，使用循环读完\n",
    "# 尽量保持格式"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# seek（offset， from)\n",
    "- 移动文件的读取位置，也叫读取指针\n",
    "- from的取值范围：\n",
    "    - 0： 从文件头开始偏移\n",
    "    - 1：从文件当前位置开始偏移\n",
    "    - 2： 从文件末尾开始偏移\n",
    "- 移动的单位是字节(byte)\n",
    "- 一个汉子由若干个字节构成\n",
    "- 返回文件只针对 当前位置"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "他日相逢\n",
      "我将何以贺你\n",
      "以沉默\n",
      "以眼泪\n"
     ]
    }
   ],
   "source": [
    "# seek案例\n",
    "# 打开文件后，从第5个字节出开始读取\n",
    "\n",
    "# 打开读写指针在0处， 即文件的开头\n",
    "with open(r'test01.txt', 'r') as f:\n",
    "    # seek移动单位是字节\n",
    "    f.seek(6, 0)\n",
    "    strChar = f.read()\n",
    "    print(strChar)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "假若他\n",
      "日相逢\n",
      "\n",
      "我将\n",
      "何以贺\n",
      "你\n",
      "以\n",
      "沉默\n",
      "\n",
      "以眼泪\n"
     ]
    }
   ],
   "source": [
    "# 关于读取文件的练习\n",
    "# 打开文件，三个字符一组读出内容，然后显示在屏幕上\n",
    "# 每读一次，休息一秒钟\n",
    "\n",
    "# 让程序暂停，可以使用time下的sleep函数\n",
    "import time\n",
    "\n",
    "with open(r'test01.txt', 'r') as f:\n",
    "    # read参数的单位是字符，可以理解成一个汉字就是一个字符\n",
    "    strChar = f.read(3)\n",
    "    while strChar:\n",
    "        print(strChar)\n",
    "        # sleep参数单位是秒\n",
    "        time.sleep(1)\n",
    "        strChar = f.read(3)\n",
    "# 作业：\n",
    "# 解释以下运行结果，为什么不是每行三个字符"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "9\n",
      "假若他\n",
      "18\n",
      "日相逢\n",
      "25\n",
      "\n",
      "我将\n",
      "34\n",
      "何以贺\n",
      "41\n",
      "你\n",
      "以\n",
      "48\n",
      "沉默\n",
      "\n",
      "57\n",
      "以眼泪\n"
     ]
    }
   ],
   "source": [
    "# tell函数： 用来显示文件读写指针的当前位置\n",
    "with open(r'test01.txt', 'r') as f:\n",
    "    strChar = f.read(3)\n",
    "    pos = f.tell()\n",
    "    \n",
    "    while strChar:\n",
    "        print(pos)\n",
    "        print(strChar)\n",
    "        \n",
    "        strChar = f.read(3)\n",
    "        pos = f.tell()\n",
    "        \n",
    "# 以下结果说明：\n",
    "# tell的返回数字的单位是byte\n",
    "# read是以字符为单位"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 文件的写操作-write\n",
    "- write(str): 把字符串写入文件\n",
    "- writeline(str): 把字符串按行写入文件\n",
    "- 区别：\n",
    "    - write函数参数只能是字符串\n",
    "    - writerline参数可以是字符串，也可以是字符序列"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# write 案例\n",
    "# 1. 向文件追加一句诗\n",
    "\n",
    "# a代表追加方式打开\n",
    "with open(r'test01.txt', 'a') as f:\n",
    "    # 注意字符串内含有换行符\n",
    "    f.write(\"生活不仅有眼前的苟且， \\n 还有远方的苟且\")\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 可以直接写入行， 用writelines\n",
    "# writelines表示写入很多行，参数可以是list格式\n",
    "\n",
    "# a代表追加方式打开\n",
    "with open(r'test01.txt', 'a') as f:\n",
    "    # 注意字符串内含有换行符\n",
    "    f.writelines(\"生活不仅有眼前的苟且\")\n",
    "    f.writelines(\"还有远方的枸杞\")\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "l = [\"I\", \"love\", \"wangxiaojing\"]\n",
    "\n",
    "# a代表追加方式打开\n",
    "with open(r'test01.txt', 'w') as f:\n",
    "    # 注意字符串内含有换行符\n",
    "    f.writelines(l)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 持久化 - pickle\n",
    "- 序列化（持久化，落地）：把程序运行中的信息保存在磁盘上\n",
    "- 反序列化： 序列号的逆过程\n",
    "- pickle： python提供的序列化模块\n",
    "- pickle.dump:序列化\n",
    "- pickle.load:反序列化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 序列化案例\n",
    "import pickle\n",
    "\n",
    "age = 19\n",
    "\n",
    "with open(r'test01.txt', 'wb') as f:\n",
    "    pickle.dump(age, f)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "19\n"
     ]
    }
   ],
   "source": [
    "# 反序列化案例\n",
    "\n",
    "import pickle\n",
    "\n",
    "with open(r'test01.txt', 'rb') as f:\n",
    "    age = pickle.load(f)\n",
    "    print(age)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 序列化案例\n",
    "import pickle\n",
    "\n",
    "a = [19, 'liudana', \"i love wangxiaojing\", [185, 76]]\n",
    "\n",
    "with open(r'test01.txt', 'wb') as f:\n",
    "    pickle.dump(a, f)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[19, 'liudana', 'i love wangxiaojing', [185, 76]]\n"
     ]
    }
   ],
   "source": [
    "\n",
    "with open(r'test01.txt', 'rb') as f:\n",
    "    a  = pickle.load(f)\n",
    "    print(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 持久化-shelve\n",
    "- 持久化工具\n",
    "- 类似字典，用kv对保存数据，存取方式跟字典也类似\n",
    "- open, close"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 使用shelve创建文件并使用\n",
    "import shelve\n",
    "\n",
    "# 打开文件\n",
    "# shv相当于一个字典\n",
    "shv = shelve.open(r'shv.db')\n",
    "\n",
    "shv['one'] = 1\n",
    "shv['two'] = 2\n",
    "shv['three'] = 3\n",
    "\n",
    "shv.close()\n",
    "\n",
    "# 通过以上案例发现，shelve自动创建的不仅仅是一个shv.db文件，还包括其他格式文件"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "烦死了\n"
     ]
    }
   ],
   "source": [
    "# shelve读取案例\n",
    "shv = shelve.open(r'shv.db')\n",
    "\n",
    "try:\n",
    "    print(shv['one'])\n",
    "    print(shv['threee'])\n",
    "except Exception as e:\n",
    "    print(\"烦死了\")\n",
    "finally:\n",
    "    shv.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# shelve特性\n",
    "- 不支持多个应用并行写入\n",
    "    - 为了解决这个问题，open的时候可以使用flag=r\n",
    "- 写回问题\n",
    "    - shelv恶魔人情况下不会等待持久化对象进行任何修改\n",
    "    - 解决方法： 强制写回：writeback=True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n"
     ]
    }
   ],
   "source": [
    "# shelve 之只读打开\n",
    "import shelve\n",
    "\n",
    "shv = shelve.open(r'shv.db', flag='r')\n",
    "\n",
    "try:\n",
    "    k1 = shv['one']\n",
    "    print(k1)\n",
    "finally:\n",
    "    shv.close()\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'eins': 1, 'zwei': 2, 'drei': 3}\n"
     ]
    }
   ],
   "source": [
    "import shelve\n",
    "\n",
    " \n",
    "\n",
    "shv = shelve.open(r'shv.db')\n",
    "try:\n",
    "    shv['one'] = {\"eins\":1, \"zwei\":2, \"drei\":3}\n",
    "finally:\n",
    "    shv.close()\n",
    "\n",
    "\n",
    "shv = shelve.open(r'shv.db')\n",
    "try:\n",
    "    one = shv['one']\n",
    "    print(one)\n",
    "finally:\n",
    "    shv.close()\n",
    "    \n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'eins': 1, 'zwei': 2, 'drei': 3}\n",
      "{'eins': 1, 'zwei': 2, 'drei': 3}\n"
     ]
    }
   ],
   "source": [
    "# shelve忘记写回，需要使用强制写回\n",
    "shv = shelve.open(r'shv.db')\n",
    "try:\n",
    "    k1 = shv['one']\n",
    "    print(k1)\n",
    "    # 此时，一旦shelve关闭，则内容还是存在于内存中，没有写回数据库\n",
    "    k1[\"eins\"] =100\n",
    "finally:\n",
    "    shv.close()\n",
    "    \n",
    "    \n",
    "shv = shelve.open(r'shv.db')\n",
    "try:\n",
    "    k1 = shv['one']\n",
    "    print(k1)\n",
    "finally:\n",
    "    shv.close()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'eins': 1, 'zwei': 2, 'drei': 3}\n",
      "{'eins': 100, 'zwei': 2, 'drei': 3}\n"
     ]
    }
   ],
   "source": [
    "# shelve忘记写回，需要使用强制写回\n",
    "shv = shelve.open(r'shv.db', writeback=True)\n",
    "try:\n",
    "    k1 = shv['one']\n",
    "    print(k1)\n",
    "    # 此时，一旦shelve关闭，则内容还是存在于内存中，没有写回数据库\n",
    "    k1[\"eins\"] =100\n",
    "finally:\n",
    "    shv.close()\n",
    "    \n",
    "    \n",
    "shv = shelve.open(r'shv.db')\n",
    "try:\n",
    "    k1 = shv['one']\n",
    "    print(k1)\n",
    "finally:\n",
    "    shv.close()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'eins': 100, 'zwei': 2, 'drei': 3}\n",
      "{'eins': 1000, 'zwei': 2, 'drei': 3}\n"
     ]
    }
   ],
   "source": [
    "# shelve 使用with管理上下文环境\n",
    "\n",
    "with shelve.open(r'shv.db', writeback=True) as shv:\n",
    "    k1 = shv['one']\n",
    "    print(k1)\n",
    "    # 此时，一旦shelve关闭，则内容还是存在于内存中，没有写回数据库\n",
    "    k1[\"eins\"] =1000\n",
    "\n",
    "    \n",
    "    \n",
    "with shelve.open(r'shv.db') as shv:\n",
    "    print(shv['one'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
